A return type containing wildcards cannot be narrowed down in any context. This indicates that the developer’s intention was likely something
else.
The core problem lies in type variance. Expressions at an input position, such as arguments passed to a method, can have a more specific type than
the type expected by the method, which is called covariance. Expressions at an output position, such as a variable that receives the return
result from a method, can have a more general type than the method’s return type, which is called contravariance. This can be traced back to
the Liskov substitution principle.
In Java, type parameters of a generic type are invariant by default due to their potential occurrence in both input and output positions at the
same time. A classic example of this is the methods T get()
(output position) and add(T element)
(input position) in
interface java.util.List
. We could construct cases with invalid typing in List
if T
were not invariant.
Wildcards can be employed to achieve covariance or contravariance in situations where the type parameter appears in one position only:
-
<? extends Foo>
for covariance (input positions)
-
<? super Foo>
for contravariance (output positions)
However, covariance is ineffective for the return type of a method since it is not an input position. Making it contravariant also has no effect
since it is the receiver of the return value which must be contravariant (use-site variance in Java). Consequently, a return type containing wildcards
is generally a mistake.